/*
    Copyright 2006 Todi.
    Send feedback and suggestions to todi@peerfeeds.com.  
  
    This file is part of Peerfeeds.

    Peerfeeds is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Peerfeeds is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Peerfeeds; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
  
*/
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Resources;
using System.Runtime.InteropServices;
using System.Configuration;
using System.Timers;
using System.Reflection;

namespace Peerfeeds
{
    public partial class Peerfeeds : Form
    {
        private ArrayList feedsCache = new ArrayList();
        private DateTime lastFeedsRead;
        private string versionString = "Peerfeeds 1.1 [b1]";


        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Peerfeeds());
        }

        #region Timer

        private void InitiateTimer()
        {
            int interval = Convert.ToInt32(ConfigurationManager.AppSettings["Interval"]);
            System.Timers.Timer aTimer = new System.Timers.Timer();

            // Set a minimum interval time. Gettings feeds too often will cause bans
            if (interval < 15)
            {
                interval = 15;
            }

            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            aTimer.Interval = (interval * 60000);
            aTimer.Enabled = true;
        }

        // Specify what you want to happen when the Elapsed event is raised.
        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            RetrieveRSS();
        }

        #endregion

        private Peerfeeds()
        {
            // Start timer
            InitiateTimer();

            // Constructor for the form
            InitializeComponent();

            // Keep the form hidden
            this.Hide();

            // Create the MenuItem objects
            MenuItem[] mnuItems = new MenuItem[8];

            // Create the menu items array
            mnuItems[0] = new MenuItem("Retrieve RSS feeds now", this.MenuRetrieveRSS);
            mnuItems[0].DefaultItem = true;
            mnuItems[1] = new MenuItem("(feeds update every " + (ConfigurationManager.AppSettings["Interval"]) + " minutes)");
            mnuItems[2] = new MenuItem("-");
            mnuItems[3] = new MenuItem("Open feed manager", this.Open);
            mnuItems[4] = new MenuItem("View last status message", this.MenuShowStatus);
            mnuItems[5] = new MenuItem("View error log", this.MenuShowErrors);
            mnuItems[6] = new MenuItem("-");
            mnuItems[7] = new MenuItem("Exit", this.MenuExit);

            // Add the menu items to the context menu of the NotifyIcon
            ContextMenu notifyIconMenu = new ContextMenu(mnuItems);
            notifyIcon.ContextMenu = notifyIconMenu;
            notifyIcon.Text = versionString;
            
            Bitmap bmp = LoadEmbeddedImage("Peerfeeds.Resources.tray.bmp");
            // the color from the left bottom pixel will be made transparent

            m_DefaultIcon = notifyIcon.Icon;

            bmp.MakeTransparent();
            SetAnimationClip(bmp);

            notifyIcon.Icon = m_animationIcons[0];

            //RetrieveRSS();

            // Temporary always open manager to speed development
            Manager form = new Manager();
            form.ShowDialog();
        }

        private void RetrieveRSS()
        {
            Program pf = new Program();

            StartAnimation(150, 15);

            notifyIcon.Text = pf.versionString + Environment.NewLine + "Retrieving rss feeds...";

            BalloonStatus status = pf.RetrieveRSS(ref lastFeedsRead, ref feedsCache);

            SetBalloonTip(status.title, status.text, status.icon);
            notifyIcon.Text = pf.versionString;

            StopAnimation();

            pf.WriteErrors("error.log");
        }

       #region AnimatedIcon

        private Icon[] m_animationIcons;
        private System.Timers.Timer m_timer;
        private int m_currIndex = 0;
        private int m_loopCount = 0;
        private Icon m_DefaultIcon;

        public void StartAnimation(int interval, int loopCount)
        {
            m_timer = new System.Timers.Timer();
            m_timer.Elapsed += new ElapsedEventHandler(m_timer_Tick);

            m_loopCount = loopCount;
            m_timer.Interval = interval;
            m_timer.Start();
        }

        private void StopAnimation()
        {
            m_timer.Stop();
            m_timer.Dispose();
            notifyIcon.Icon = m_animationIcons[0];
        }

        public void SetAnimationClip(Bitmap bitmapStrip)
        {
            m_animationIcons = new Icon[bitmapStrip.Width / 16];

            for (int i = 0; i < m_animationIcons.Length; i++)
            {
                Rectangle rect = new Rectangle(i * 16, 0, 16, 16);
                Bitmap bmp = bitmapStrip.Clone(rect, bitmapStrip.PixelFormat);
                m_animationIcons[i] = Icon.FromHandle(bmp.GetHicon());
            }
        } 

        private void m_timer_Tick(object sender, EventArgs e)
        {
            if (m_currIndex < m_animationIcons.Length)
            {
                notifyIcon.Icon = m_animationIcons[m_currIndex];
                m_currIndex++;
            }
            else
            {
                m_currIndex = 0;
            }
       }

        /*
        private void m_timer_Tick(object sender, EventArgs e)
        {
            if (m_currIndex > m_animationIcons.Length -1)
            {
              m_currIndex = 0;
              if (m_loopCount <= 0)
              {
                m_timer.Stop();
                m_notifyIcon.Icon = m_DefaultIcon;
              }
              else
              {
                --m_loopCount;
              }
            }
            m_notifyIcon.Icon =     m_animationIcons[m_currIndex];
            m_currIndex++;
        } 
        */    

       #endregion

       #region Context Menu Events
        
       private void Open(object sender, EventArgs e)
       {
           Manager form = new Manager();
           form.ShowDialog();
       }


       private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
       {
           if (notifyIcon.BalloonTipText.Length > 0)
           {
               notifyIcon.ShowBalloonTip(120);
           }
       }

       private void MenuRetrieveRSS(object sender, EventArgs e)
       {
           RetrieveRSS();
       }

       private void MenuShowStatus(object sender, EventArgs e)
       {
           if (notifyIcon.BalloonTipText.Length > 0)
           {
               notifyIcon.ShowBalloonTip(120);
           }
       }

       private void MenuShowErrors(object sender, EventArgs e)
       {
           // TODO: Change to read error.log

           System.Diagnostics.Process.Start("error.log");

           //if (errorLog.Count > 0)
           //{
           //    string tempTitle = notifyIcon.BalloonTipTitle;
           //    string tempText = notifyIcon.BalloonTipText;
           //    ToolTipIcon tempIcon = notifyIcon.BalloonTipIcon;

           //    StringBuilder errors = new StringBuilder();

           //    foreach (string error in errorLog)
           //    {
           //        errors.Append(error + Environment.NewLine);
           //    }

           //    BalloonError("Found " + errorLog.Count + " error(s)", errors.ToString());
           //    SetBalloonTip(tempTitle, tempText, tempIcon);
           //}
       }

       private void MenuExit(object sender, EventArgs e)
       {
           notifyIcon.Visible = false;
           this.Close();
       }

       #endregion

       #region Balloon Tips

       //public void BalloonInfo(string title, string text)
       //{
       //    SetBalloonTip(title, text, ToolTipIcon.Info);
       //    ShowBalloonTip();
       //}

       //public void BalloonError(string title, string text)
       //{
       //    SetBalloonTip(title, text, ToolTipIcon.Error);
       //    ShowBalloonTip();
       //}

       private void SetBalloonTip(string title, string text, ToolTipIcon icon)
       {
           notifyIcon.BalloonTipTitle = title;
           notifyIcon.BalloonTipText = text;
           notifyIcon.BalloonTipIcon = icon;
           ShowBalloonTip();
       }

       private void ShowBalloonTip()
       {
           uint test = Win32.GetIdleTime();

           // If the user is away, we don't want them to have hundreds of balloons when they get back.
           // Therefore we'll only show the ballon if the user has been active during the last 10 minutes
           if (Win32.GetIdleTime() < (10 * 60000))
           {
               notifyIcon.ShowBalloonTip(30);
           }
       }

       #endregion

       //private void AddError(string error)
       //{
           // TODO: Write to error.log

           // We can only fit 3-4 errors into the balloon so.. not the best solution, but it works.
           //if (errorLog.Count >= 4)
           //{
           //    errorLog.RemoveAt(0);
           //}
           //errorLog.Add(error);
       //}

         
       /*         
        This code was not written by me. It's used to see if the user is idle (or using keyboard/mouse).
        It was taken from http://www.codeproject.com/csharp/GetIdleTimeWithCS.asp. Author was Xavi23cr.
       */
       public class Win32
       {
            [DllImport("User32.dll")]
            private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

            public static uint GetIdleTime()
            {
                LASTINPUTINFO lastInPut = new LASTINPUTINFO();
                lastInPut.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInPut);
                GetLastInputInfo(ref lastInPut);

                return ((uint)Environment.TickCount - lastInPut.dwTime);
            }
        }

        internal struct LASTINPUTINFO
        {
            public uint cbSize;
            public uint dwTime;
        }
        
        private Bitmap LoadEmbeddedImage(string name)
        {
            Assembly a = Assembly.GetExecutingAssembly();

            //string[] resNames = a.GetManifestResourceNames();

            System.IO.Stream s =
               a.GetManifestResourceStream(name);

            Image img = Image.FromStream(s);
            Bitmap bmp = new Bitmap(img);

            return bmp;
        }
    }
}
